#include "dht11.h"
#include "delay.h"
#include <stdio.h>

/*DHT11复位和检测响应函数，返回值：1-检测到响应信号；0-未检测到响应信号*/
u8 DHT11RstAndCheck(void)
{
    u8 timer = 0;

    __set_PRIMASK(1);          //关总中断
    DHT11_OUT = 0; 	           //输出低电平
    delay_ms(20);    	       //拉低至少18ms
    DHT11_OUT = 1; 	           //输出高电平
    delay_us(30);     	       //拉高20~40us
    while (!DHT11_IN)          //等待总线拉低，DHT11会拉低40~80us作为响应信号
    {
        timer++;               //总线拉低时计数
        delay_us(1);
    }
    if (timer>100 || timer<20) //判断响应时间
    {
        __set_PRIMASK(0);      //开总中断
        return 0;
    }
	
    timer = 0;
    while (DHT11_IN)           //等待DHT11释放总线，持续时间40~80us
    {
        timer++;               //总线拉高时计数
        delay_us(1);
    }
    __set_PRIMASK(0);          //开总中断
    if (timer>100 || timer<20) //检测响应信号之后的高电平
    {
        return 0;
    }
	
    return 1;
}

/*读取一字节数据，返回值-读到的数据*/
u8 DHT11ReadByte(void)
{
    u8 i;
    u8 byt = 0;

    __set_PRIMASK(1);      //关总中断
    for (i=0; i<8; i++)
    {
        while (DHT11_IN);  //等待低电平，数据位前都有50us低电平时隙
		
        while (!DHT11_IN); //等待高电平，开始传输数据位
		
        delay_us(40);
        byt <<= 1;         //因高位在前，所以左移byt，最低位补0
        if (DHT11_IN)      //将总线电平值读取到byt最低位中
        {
            byt |= 0x01;
        }
    }
    __set_PRIMASK(0);      //开总中断

    return byt;
}

/*读取一次数据，返回参数：Humi-湿度,Temp-温度；返回值: 0-成功，1-失败*/
u8 DHT11ReadData(float *Humi, float *Temp)
{
    s8 sta = 0;
    u8 i;
    u8 buf[5];

    if (DHT11RstAndCheck())         //检测响应信号
    {
        for(i=0;i<5;i++)            //读取40位数据
        {
            buf[i]=DHT11ReadByte(); //读取1字节数据
        }
        if(buf[0]+buf[1]+buf[2]+buf[3] == buf[4]) //校验成功
        {
            u8 H_inte = buf[0]; //湿度整数部分数据
			u8 H_frac = buf[1]; //湿度小数部分数据
            u8 T_inte = buf[2]; //温度整数部分数据
			u8 T_frac = buf[3]; //温度小数部分数据
			
			char tmp1[8], tmp2[8];
			sprintf(tmp1, "%d.%d",H_inte,H_frac);
			sscanf(tmp1, "%f", Humi);
			sprintf(tmp2, "%d.%d",T_inte,T_frac);
			sscanf(tmp2, "%f", Temp);
        }
        sta = 0;
    }
    else //响应失败返回-1
    {
        *Humi = 88; //响应失败返回88
        *Temp = 88; //响应失败返回88
        sta = 1;
    }
    
    return sta;    
}

/*DHT11初始化函数*/
u8 DHT11Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//使能GPIOC端口时钟
    GPIO_SetBits(GPIOB,GPIO_Pin_8);                     //设置PC13输出高电平，(先设置引脚电平可以避免IO初始化过程中可能产生的毛刺)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;	        //设置DHT11数据引脚->PC13
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;    //设置为开漏输出模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //设置输出速率为50MHz
    GPIO_Init(GPIOB, &GPIO_InitStructure);	            //初始化GPIOC端口

    return DHT11RstAndCheck();                          //返回DHT11状态
}
